import { IGetDecisionFlowNodeVariablesRes } from '@/api';
import { NODE_LIST, NODE_TYPE } from '@/constants/config';
import { TResultItem } from '@/store/node-results';
import { TverificationItem } from '@/store/node-verification';
import { Edge, Graph, Path } from '@antv/x6';
import { PortManager } from '@antv/x6/lib/model/port';
import { formatConditions } from '@/utils/edge-process';

export const createPortNameWithNodeType = (
  nodeType: keyof typeof NODE_TYPE,
  direction: 'left' | 'right'
) => {
  return nodeType + '_port_' + direction;
};

export const createGraphNode = (
  graph: Graph,
  nodeType: keyof typeof NODE_TYPE,
  data: any
) => {
  const ports: Partial<PortManager.Metadata> | PortManager.PortMetadata[] = [
    {
      id: createPortNameWithNodeType(nodeType, 'left'),
      group: 'in'
    },
    {
      id: createPortNameWithNodeType(nodeType, 'right'),
      group: 'out'
    }
  ];
  if (nodeType === NODE_TYPE.START) {
    ports.splice(0, 1);
  } else if (nodeType === NODE_TYPE.END) {
    ports.splice(1, 1);
  }

  const initData = {
    ...data,
    nodeType
  } as any;

  if (NODE_LIST[nodeType]) {
    Object.assign(initData, NODE_LIST[nodeType]);
  }

  const node = graph!.createNode({
    shape: nodeType,
    data: initData,
    ports
  });

  return node;
};

export const registerEdge = () => {
  Graph.registerConnector(
    'curveConnector',
    (sourcePoint, targetPoint) => {
      const hgap = Math.abs(targetPoint.x - sourcePoint.x);
      const path = new Path();
      path.appendSegment(
        Path.createSegment('M', sourcePoint.x - 4, sourcePoint.y)
      );
      path.appendSegment(
        Path.createSegment('L', sourcePoint.x + 12, sourcePoint.y)
      );
      // 水平三阶贝塞尔曲线
      path.appendSegment(
        Path.createSegment(
          'C',
          sourcePoint.x < targetPoint.x
            ? sourcePoint.x + hgap / 2
            : sourcePoint.x - hgap / 2,
          sourcePoint.y,
          sourcePoint.x < targetPoint.x
            ? targetPoint.x - hgap / 2
            : targetPoint.x + hgap / 2,
          targetPoint.y,
          targetPoint.x - 6,
          targetPoint.y
        )
      );
      path.appendSegment(
        Path.createSegment('L', targetPoint.x + 2, targetPoint.y)
      );

      return path.serialize();
    },
    true
  );

  Edge.config({
    markup: [
      {
        tagName: 'path',
        selector: 'wrap',
        attrs: {
          fill: 'none',
          cursor: 'pointer',
          stroke: 'transparent',
          strokeLinecap: 'round'
        }
      },
      {
        tagName: 'path',
        selector: 'line',
        attrs: {
          fill: 'none',
          pointerEvents: 'none'
        }
      }
    ],
    connector: { name: 'curveConnector' },
    attrs: {
      wrap: {
        connection: true,
        strokeWidth: 10,
        strokeLinejoin: 'round'
      },
      line: {
        connection: true,
        stroke: '#A2B1C3',
        strokeWidth: 1,
        targetMarker: {
          name: 'classic',
          size: 6
        }
      }
    }
  });

  Graph.registerEdge('base-edge', Edge, true);
};

export const setNodeDataById = (graph: Graph, nodeId: string, data: any) => {
  const node = graph.getCellById(nodeId);
  if (node) {
    node.setData(data);
  }
};

export const findParentNode = (graph: Graph, node: any) => {
  const parent = graph.getCellById(node.parent);
  if (parent) {
    return parent;
  }
  return null;
};

export type TVariables = IGetDecisionFlowNodeVariablesRes[0];

/**
 * 查找父级节点的变量
 * @param graph 实例
 * @param nodeId id
 */
export const findParentVariables = (
  graph: Graph | null,
  nodeId: string,
  variableType: 'private' | 'node' | 'condition'
) => {
  const result: TVariables[] = [];

  const getEdgeByTargetId = (targetId: string) => {
    return graph!
      .getEdges()
      ?.find((item) => item.getTargetCell()?.id === targetId);
  };
  const setVariablesByNodeId = (id: string) => {
    const variables = findVariables(graph, id, variableType);
    result.push(...variables);
  };
  const findParent = (id: string, noSave = false) => {
    const node = graph?.getCellById(id);
    if (node && node.shape) {
      if (node.shape === 'base-edge') {
        if (!noSave) {
          setVariablesByNodeId(id);
        }
        const sourceId = (node as Edge<Edge.Properties>).getSourceCell()?.id;
        findParent(sourceId!);
      } else {
        if (!noSave) {
          setVariablesByNodeId(id);
        }
        const edge = getEdgeByTargetId(id);
        if (edge) {
          findParent(edge.id);
        }
      }
    }
  };

  findParent(nodeId, true);

  return result;
};

/**
 * 查找父级节点的变量
 * @param graph 实例
 * @param nodeId id
 */
export const findVariables = (
  graph: Graph | null,
  nodeId: string,
  variableType: 'private' | 'node' | 'condition'
) => {
  const data = graph?.getCellById(nodeId!)?.getData();
  return (
    (variableType === 'private' ? data.variables : data.nodeVariables) || []
  );
};

export const getAllVariables = (
  graph: Graph | null,
  variableType: 'private' | 'node' | 'condition'
) => {
  const cells = graph?.getCells();
  const variables: TVariables[] = [];

  cells?.map((cell) => {
    const data = cell.getData();

    if (variableType === 'private') {
      return variables.push(...(data.variables?.filter(Boolean) || []));
    }

    return variables.push(...(data.nodeVariables?.filter(Boolean) || []));
  });

  return variables;
};

/** 根据执行结果展示结果样式 */
export const showNodeStatusWithState = (
  graph: Graph,
  data: TResultItem,
  withLoading = true
) => {
  const isNode = !!data.nodeId;
  const useLoading =
    ['WAITING', 'RUNNING', 'REJECT'].includes(data.execStatus!) === false;
  if (isNode) {
    graph?.getCellById(data.nodeId!)?.getData().setNodeData?.({
      status: data.execStatus
    });
    if (withLoading && useLoading) {
      graph.getEdges().map((edge) => {
        if (edge.getSourceCellId() === data.nodeId) {
          edge.attr({
            line: {
              stroke: '#3471F9',
              strokeDasharray: 5,
              style: {
                animation: 'running-line 10s infinite linear'
              }
            }
          });
        }
      });
    }
  } else {
    const edge = graph?.getCellById(data.lineId!) as Edge;
    edge?.attr({
      line: {
        stroke: data.execStatus === 'PASS' ? '#52c41a' : '#f00',
        strokeDasharray: 0,
        strokeWidth: 1.5,
        style: {
          animation: ''
        }
      }
    });

    if (withLoading && useLoading) {
      edge.getTargetNode()?.getData().setNodeData?.({
        status: 'RUNNING'
      });
    }
  }
};

/** 根据校验结果展示结果样式 */
export const showNodeStatusWithVerification = (
  graph: Graph,
  data: TverificationItem
) => {
  const isNode = !!data.nodeId;
  // const useLoading = ['WAITING', 'RUNNING', 'REJECT'].includes(data.execStatus!) === false;
  if (isNode) {
    graph?.getCellById(data.nodeId!)?.getData().setNodeData?.({
      status: data.execStatus
    });
    // if (withLoading && useLoading) {
    //   graph.getEdges().map((edge) => {
    //     if (edge.getSourceCellId() === data.nodeId) {
    //       edge.attr({
    //         line: {
    //           stroke: '#3471F9',
    //           strokeDasharray: 5,
    //           style: {
    //             animation: 'running-line 10s infinite linear'
    //           }
    //         }
    //       });
    //     }
    //   });
    // }
  } else {
    const edge = graph?.getCellById(data.lineId!) as Edge;
    edge?.attr({
      line: {
        stroke: data.execStatus === 'PASS' ? '#52c41a' : '#f00',
        strokeDasharray: 0,
        strokeWidth: 1.5,
        style: {
          animation: ''
        }
      }
    });
    const assignmentList = edge?.getData().condition;

    // const assignmentList = currentNode.getCondition();
    const strList: string[] = [];
    assignmentList?.forEach((assignment) => {
      const formattedConditions = formatConditions(
        assignment.conditions.conditions,
        assignment.conditions.conjs
      );
      formattedConditions && strList.push(formattedConditions);
    });
    if (strList && strList.length) {
      edge?.setLabels([
        {
          attrs: {
            label: { text: strList.join('\n\n') },
            text: {
              fill:
                data && data.errorMsg && data.errorMsg.length
                  ? 'var(--color-red-6)'
                  : 'var(--color-blue-6)',
              fontSize: 12,
              textAnchor: 'middle',
              textVerticalAnchor: 'middle'
            },
            rect: {
              ref: 'label',
              fill:
                data && data.errorMsg && data.errorMsg.length
                  ? 'var(--color-red-1)'
                  : 'var(--color-blue-1)',
              stroke:
                data && data.errorMsg && data.errorMsg.length
                  ? 'var(--color-red-4)'
                  : 'var(--color-blue-4)',
              refWidth: 14,
              refHeight: 5,
              refX: -7,
              refY: -2.5,
              rx: 20,
              ry: 20
            }
          },
          position: {
            distance: 0.5
          }
        }
      ]);
    } else {
      edge?.setLabels([]);
    }

    // if (withLoading && useLoading) {
    //   edge.getTargetNode()?.getData().setNodeData?.({
    //     status: 'RUNNING'
    //   });
    // }
  }
};
